package net.groupme.gui.rendering;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang.StringEscapeUtils;

import net.groupme.controller.model.HtmlFormattedElement;
import net.groupme.gui.constants.VIEW_VOCABULARY;
import net.groupme.gui.rendering.constants.RENDERING_CONSTANTS;
import net.groupme.model.Tag;
import net.groupme.search.strategy.model.WeightedIdentifiableComparatorByLabel;
import net.groupme.search.strategy.model.WeightedIdentifiableComparatorByWeight;
import net.groupme.search.strategy.model.WeightedResource;
import net.groupme.search.strategy.model.WeightedTag;



/**
 * created on 02.07.2007
 * 
 * This class renders a Tag to a {@link HtmlFormattedElement}.
 * 
 * @author Mischa Frank, <a href="mailto:code@planetfrank.net">code@planetfrank.net</a>
 * @author last edited by: $Author: nicole $
 * 
 * @version $Revision: 1.19 $ $Date: 2008-11-05 11:56:22 $
 */
public class TagRenderer {

	/**
	 * Renders a given Tag as Hyperlink
	 * @param tag the tag to render
	 * @return given Tag as Hyperlink
	 */
	public String renderAsHTML(Tag tag) {	
		return renderTagAsHtmlString(tag, 1.0);
	}
	
	/**
	 * Renders a given list of {@link WeightedResource} instances as tag cloud.
	 * 
	 * @param tags the list of weighted tags
	 * @return String which contains Tag-Hyperlinks with different sizes. 
	 */
	public String renderTagCloud(List<WeightedTag> tags){
		String tagCloud = "";
		if(tags == null || tags.isEmpty()){
			return tagCloud;
		}
		//Sort tags according to weight:
		Collections.sort(tags, new WeightedIdentifiableComparatorByWeight());
		
		/* Formel: size = a * weight + b
		 * Also:
		 *        maxSize - minSize
		 *   a = ----------------------
		 *       maxWeight - minWeight
		 *   
		 *   b = minSize - a * minWeight
		 */
		Double maxWeight = tags.get(0).getWeight();
		Double minWeight = tags.get(tags.size()-1).getWeight();
		Double a = 0.0;
		Double b = 0.0;
		a = (RENDERING_CONSTANTS.TAG_SIZE_MAXIMUM - RENDERING_CONSTANTS.TAG_SIZE_MINIMUM) / (maxWeight - minWeight);
		b = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM - a * minWeight;
		
		//Sort tags according to their labels (= keywords):
		Collections.sort(tags, new WeightedIdentifiableComparatorByLabel());
		Double size = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM;
		for(int i=0; i < tags.size(); i++){
			size = a * tags.get(i).getWeight() + b;
			if(renderTagAsHtmlString(tags.get(i).tag, size) != null)
				//check wether the tag contains any forbidden characters
				if(checkTag(tags.get(i).tag) != null)
					tagCloud += renderTagAsHtmlString(tags.get(i).tag, size) + " ";
		}

		return tagCloud;
	}
	
	/**
	 * Renders a given list of {@link WeightedResource} instances as tag cloud
	 * for background of groupedit.
	 * 
	 * @param tags the list of weighted tags
	 * @return String which contains Tag-Hyperlinks with different sizes. 
	 */
	public String renderBackgroundTagCloud(List<WeightedTag> tags){
		String tagCloud = "";
		if(tags == null || tags.isEmpty()){
			return tagCloud;
		}
		//Sort tags according to weight:
		Collections.sort(tags, new WeightedIdentifiableComparatorByWeight());
		
		/* Formel: size = a * weight + b
		 * Also:
		 *        maxSize - minSize
		 *   a = ----------------------
		 *       maxWeight - minWeight
		 *   
		 *   b = minSize - a * minWeight
		 */
		Double maxWeight = tags.get(0).getWeight();
		Double minWeight = tags.get(tags.size()-1).getWeight();
		Double a = 0.0;
		Double b = 0.0;
		a = (RENDERING_CONSTANTS.TAG_SIZE_MAXIMUM - RENDERING_CONSTANTS.TAG_SIZE_MINIMUM) / (maxWeight - minWeight);
		b = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM - a * minWeight;
		
		//Sort tags according to their labels (= keywords):
		Collections.sort(tags, new WeightedIdentifiableComparatorByLabel());
		Double size = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM;
		for(int i=0; i < tags.size(); i++){
			size = a * tags.get(i).getWeight() + b;
			//check wether the tag contains any forbidden characters
			if(checkTag(tags.get(i).tag) != null)
				tagCloud += renderTagAsHtmlStringNoHyperlink(tags.get(i).tag, size) + " ";
		}

		return tagCloud;
	}
	
	/**
	 * Renders a given list of {@link WeightedResource} instances as tag cloud.
	 * 
	 * @param tags the list of weighted tags
	 * @return String which contains Tag-Hyperlinks with different sizes. 
	 */
	public String renderTagCloudSmall(List<WeightedTag> tags){
		String tagCloud = "";
		if(tags == null || tags.isEmpty()){
			return tagCloud;
		}
		//Sort tags according to weight:
		Collections.sort(tags, new WeightedIdentifiableComparatorByWeight());
		
		/* Formel: size = a * weight + b
		 * Also:
		 *        maxSize - minSize
		 *   a = ----------------------
		 *       maxWeight - minWeight
		 *   
		 *   b = minSize - a * minWeight
		 */
		Double maxWeight = tags.get(0).getWeight();
		Double minWeight = tags.get(tags.size()-1).getWeight();
		Double a = 0.0;
		Double b = 0.0;
		a = (RENDERING_CONSTANTS.TAG_SIZE_MAXIMUM - RENDERING_CONSTANTS.TAG_SIZE_MINIMUM) / (maxWeight - minWeight);
		b = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM - a * minWeight;
		
		//Sort tags according to their labels (= keywords):
		Collections.sort(tags, new WeightedIdentifiableComparatorByLabel());
		Double size = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM;
		for(int i=0; i < tags.size(); i++){
			size = a * tags.get(i).getWeight() + b;
			//check wether the tag contains any forbidden characters
			if(checkTag(tags.get(i).tag) != null)
				tagCloud += renderTagAsHtmlString(tags.get(i).tag, size*0.6) + " ";
		}

		return tagCloud;
	}
	
	/**
	 * Renders a given list of {@link WeightedResource} instances as tag cloud.
	 * 
	 * @param tags the list of weighted tags
	 * @return String which contains Tag-Hyperlinks with different sizes. 
	 */
	public String renderPersonalTagCloud(List<WeightedTag> tags){
		String tagCloud = "";
		if(tags == null || tags.isEmpty()){
			return tagCloud;
		}
		//Sort tags according to weight:
		Collections.sort(tags, new WeightedIdentifiableComparatorByWeight());
		
		/* Formel: size = a * weight + b
		 * Also:
		 *        maxSize - minSize
		 *   a = ----------------------
		 *       maxWeight - minWeight
		 *   
		 *   b = minSize - a * minWeight
		 */
		Double maxWeight = tags.get(0).getWeight();
		Double minWeight = tags.get(tags.size()-1).getWeight();
		Double a = 0.0;
		Double b = 0.0;
		a = (RENDERING_CONSTANTS.TAG_SIZE_MAXIMUM - RENDERING_CONSTANTS.TAG_SIZE_MINIMUM) / (maxWeight - minWeight);
		b = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM - a * minWeight;
		
		//Sort tags according to their labels (= keywords):
		Collections.sort(tags, new WeightedIdentifiableComparatorByLabel());
		Double size = RENDERING_CONSTANTS.TAG_SIZE_MINIMUM;
		for(int i=0; i < tags.size(); i++){
			size = a * tags.get(i).getWeight() + b;
			//check wether the tag contains any forbidden characters
			if(checkTag(tags.get(i).tag) != null)
				tagCloud += renderTagAsHtmlStringForPersonalTagCloud(tags.get(i).tag, size) + " ";
		}

		return tagCloud;
	}
	
	/**
	 * Renders a given list of Tags as Hyperlinks separated by commas.
	 * @param tag the tag to render
	 * @return Html-formated string which contains the list of Tags as Hyperlinks separated by commas.
	 */
	public String renderTagsAsHtmlString(Collection<Tag> tags){
		List<String> links = new ArrayList<String>();
		for(Tag tag: tags){
			links.add(renderAsHTML(tag));
		}
		return AbstractRenderer.separateStringsByComma(links);
	}

	/**
	 * Renders a given Tag as Hyperlink
	 * @param tag the tag to render
	 * @param size of the text in em (e.g. 0.8, 1.0 (= normal size) or 1.2)
	 * @return given Tag as Hyperlink
	 */
	private String renderTagAsHtmlString(Tag tag, Double size){
	if(tag.getURI() != null){
		String keyword = tag.getKeyword();
		if(keyword.contains(" ")){
			keyword = "%22" + keyword + "%22";
		}
		String keywordForHTML =  StringEscapeUtils.escapeHtml(tag.getKeyword());
		String htmlString = "<a href=\"" + tag.getURI() + "\" " 
		+ " style=\"font-size:" + size + "em\" "
		+ " title=\"Search for Groups and Resources related with " + keywordForHTML + "\"> " 
		+ keywordForHTML + "</a>";
		return htmlString;
	}
	else
		return null;
	}
	
	/**
	 * Renders a given Tag
	 * @param tag the tag to render
	 * @param size of the text in em (e.g. 0.8, 1.0 (= normal size) or 1.2)
	 * @return given Tag
	 */
	private String renderTagAsHtmlStringNoHyperlink(Tag tag, Double size){
		String keyword = tag.getKeyword();
		String keywordForHTML =  StringEscapeUtils.escapeHtml(tag.getKeyword());
		if(keyword.contains(" ")){
			keyword = "%22" + keyword + "%22";
		}
		return "<span style=\"font-size:" + size + "em\" class=\"backgroundtag\">"
		+ keywordForHTML + "</span>";
	}
	
	/**
	 * Renders a given Tag as Hyperlink
	 * @param tag the tag to render
	 * @param size of the text in em (e.g. 0.8, 1.0 (= normal size) or 1.2)
	 * @return given Tag as Hyperlink
	 */
	private String renderTagAsHtmlStringForPersonalTagCloud(Tag tag, Double size){
		String keyword = tag.getKeyword();
//		if(keyword.contains(" ")){
//			keyword = "%22" + keyword + "%22";
//		}
		String keywordForHTML =  StringEscapeUtils.escapeHtml(tag.getKeyword());
		return "<a href=\"" + VIEW_VOCABULARY.RESTful_MyGroupMe_TAG_SEARCH + keyword + "\" " 
		+ " style=\"font-size:" + size + "em\" "
		+ " title=\"Search for groups and resources tagged with " + keywordForHTML + "\"> " 
		+ keywordForHTML + "</a>";
	}
	
	/**
	 * Returns the URL that allows to search for own resources/groups that are related to the given tag.
	 * @param tag the tag to render
	 * @return given Tag as Hyperlink
	 */
	public static String getTagURLForPersonalTagCloud(Tag tag){
		String keywordForHTML =  StringEscapeUtils.escapeHtml(tag.getKeyword());
		return VIEW_VOCABULARY.RESTful_MyGroupMe_TAG_SEARCH + keywordForHTML;
	}
	
	/**
	 * Small helper function that checks wether the given tag contains "/", "?" or "\"
	 * @param tag the tag to be checked
	 * @return the tag if it doesn't contain any forbidden character otherwise null
	 */
	private Tag checkTag(Tag tag){
		
		String keyword = tag.getKeyword();
		if(keyword.contains("/") || keyword.contains("?") || keyword.contains("\\"))
			return null;
		else
			return tag;
	}

}
